#include "filetransferserverdialog.h"
#include "ui_filetransferserverdialog.h"
#include<QPalette>

FileTransferServerDialog::FileTransferServerDialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::FileTransferServerDialog)
{
    ui->setupUi(this);
    //测试Qt版本
    qDebug() << "Qt Version:" << qVersion();
    //固定窗口大小
    this->setFixedSize(width(),height());
    //调用函数返回本机IP
    QString serverAdr = getLocalIpAddressFunc();
    ui->comboBox_serverAdr->addItem(serverAdr);

    //服务器监听地址标签
    //QPalette 调色板
    QPalette pale_serverAdr = ui->label_serverAdr->palette();
    pale_serverAdr.setColor(QPalette::WindowText,Qt::yellow);
    ui->label_serverAdr->setPalette(pale_serverAdr);
    //设置字体加粗
    QFont font_serverAdr = ui->label_serverAdr->font();
    font_serverAdr.setBold(true);
    ui->label_serverAdr->setFont(font_serverAdr);

    //服务器端口地址标签
    QPalette pale_serverPort = ui->label_serverPort->palette();
    pale_serverPort.setColor(QPalette::WindowText,Qt::yellow);
    ui->label_serverPort->setPalette(pale_serverPort);
    QFont font_serverPort = ui->label_serverPort->font();
    font_serverPort.setBold(true);
    ui->label_serverPort->setFont(font_serverPort);

    //消息发送标题
    QPalette pale_sendMsg = ui->groupBox_sendMsg->palette();
    pale_sendMsg.setColor(QPalette::WindowText,Qt::yellow);
    ui->groupBox_sendMsg->setPalette(pale_sendMsg);
    QFont font_sendMsg = ui->groupBox_sendMsg->font();
    font_sendMsg.setBold(true);
    ui->groupBox_sendMsg->setFont(font_sendMsg);

    //消息列表标题
    QPalette pale_msgList = ui->groupBox_msgList->palette();
    pale_msgList.setColor(QPalette::WindowText,Qt::yellow);
    ui->groupBox_msgList->setPalette(pale_msgList);
    QFont font_msgList = ui->groupBox_msgList->font();
    font_msgList.setBold(true);
    ui->groupBox_msgList->setFont(font_msgList);

    //进度条标签
    QPalette pale_receiveFileProgress = ui->label_receiveFileProgress->palette();
    pale_receiveFileProgress.setColor(QPalette::WindowText,Qt::yellow);
    ui->label_receiveFileProgress->setPalette(pale_receiveFileProgress);
    QFont font_receiveFileProgress = ui->label_serverPort->font();
    font_receiveFileProgress.setBold(true);
    ui->label_receiveFileProgress->setFont(font_receiveFileProgress);

    //创建TCP服务器对象
    tcpServer = new QTcpServer(this);
    connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnectionFunc()));
    //创建两个tcp套接字，分别处理文本和文件传输
    tcp_textSocket = new QTcpSocket(this);
    tcp_fileSocket = new QTcpSocket(this);

    //初始化按钮状态
    ui->pushButton_send->setEnabled(false);
    ui->pushButton_stop->setEnabled(false);


    //初始化文件传输相关变量
    fileTotalBytes = 0;//文件总字节
    fileBytesReceived = 0;//已经收文件大小
    fileNameLength = 0;//文件名长度(按照字节计算)




    //文本socket连接
    connect(tcp_fileSocket,SIGNAL(connected()),this,SLOT(onFileClientConnectedFunc()));
    //托盘技术
    mySystemTrayFunc();



}

FileTransferServerDialog::~FileTransferServerDialog()
{
    delete ui;
}

//获取本地IP地址、重绘事件处理
QString FileTransferServerDialog::getLocalIpAddressFunc()
{
    QString hostName = QHostInfo::localHostName();
    QHostInfo hostInfo = QHostInfo::fromName(hostName);
    QList<QHostAddress> ipAddressList = hostInfo.addresses();
    QString hostIP = " ";
    //检查ip地址列表是否为空
    if(!ipAddressList.isEmpty())
    {
        for (int i=0;i<ipAddressList.size();i++) {
            QHostAddress addressHost = ipAddressList.at(i);
            //筛选ipv4地址
            if(addressHost.protocol() == QAbstractSocket::IPv4Protocol)
            {
                hostIP = addressHost.toString();
                break;
            }
        }
    }
    return hostIP;
}

//设置窗口背景，重绘窗口背景
void FileTransferServerDialog::paintEvent(QPaintEvent *ev)
{
    QPainter painter(this);
    //将指定的PNG图片(bgpng4.png)绘制到当前窗口/控件的整个客户区
    //rect()：目标矩形区域，表示要绘制到的范围（这里使用当前窗口/控件的完整矩形区域）
    //QPixmap(":/images/bgpng4.png")：从资源文件加载的图片对象
    //QRect()：源矩形区域（空矩形表示使用整个源图片）
    painter.drawPixmap(rect(),QPixmap(":/images/bgpng4.png"),QRect());
}

//点击启动监听按钮
void FileTransferServerDialog::on_pushButton_start_clicked()
{
    QString strAdr = ui->comboBox_serverAdr->currentText();
    quint16 port = ui->spinBox_serverPort->value();
    if(tcpServer->listen(QHostAddress(strAdr),port))
    {
        ui->plainTextEdit_msgList->appendPlainText(QString("[******* 服务器开始监听 ip:%1 port:%2 *******]").
                                                   arg(strAdr).arg(port));
        ui->pushButton_start->setEnabled(false);
        ui->pushButton_stop->setEnabled(true);

    }
}

//点击停止监听按钮
void FileTransferServerDialog::on_pushButton_stop_clicked()
{
    if(tcpServer->isListening())
    {
        tcpServer->close();
        ui->plainTextEdit_msgList->appendPlainText("[服务器已经停止监听...]");
        ui->pushButton_start->setEnabled(true);
        ui->pushButton_stop->setEnabled(false);
    }

}

//退出系统
void FileTransferServerDialog::on_pushButton_exit_clicked()
{
    this->close();
}


//点击清除消息按钮
void FileTransferServerDialog::on_pushButton_clear_clicked()
{
    ui->plainTextEdit_msgList->clear();
}

//点击发送消息按钮
void FileTransferServerDialog::on_pushButton_send_clicked()
{
    QString msg = ui->plainTextEdit_sendMsg->toPlainText();
    if(msg.isEmpty())
    {
        QMessageBox::critical(this,"错误","系统提示:消息内容不能为空");
    }
    QDateTime currentDateTime = QDateTime::currentDateTime();
    QString strDateTime = currentDateTime.toString("yyyy-MM-dd hh:mm:ss");

    msg.append('\n');
    QByteArray sendBuffer = msg.toLatin1();
    tcp_textSocket->write(sendBuffer);
    ui->plainTextEdit_msgList->appendPlainText(strDateTime + "[服务器发送消息]:"+ msg);
    ui->plainTextEdit_sendMsg->clear();
}


//TCP服务器相关槽函数
//处理新连接请求(当有客户端连接时触发)
void FileTransferServerDialog::onNewConnectionFunc()
{
    //处理文本传输通道
    if(tcp_textSocket->state() == QAbstractSocket::UnconnectedState)
    {
        //获取新的客户端连接
        tcp_textSocket = tcpServer->nextPendingConnection();

        //关联相关槽函数
        //服务端的connected()信号永远不会被发射，无需连接，因为 connected() 信号是在 Socket 状态变为 “已连接”瞬间发射的
        //，而服务器端 Socket 的 “已连接” 状态在 nextPendingConnection() 调用前就已完成（由 QTcpServer 内部处理）
        //connect(tcp_textSocket,SIGNAL(connected()),this,SLOT(onTextClientConnectedFunc()));
        connect(tcp_textSocket,SIGNAL(disconnected()),this,SLOT(onTextClientDisconnectedFunc()));
        connect(tcp_textSocket,SIGNAL(readyRead()),this,SLOT(onTextSocketReadyReadFunc()));

        ui->plainTextEdit_msgList->appendPlainText("客户端与服务器已经连接上了...");
        ui->pushButton_send->setEnabled(true);

        return;
    }


    //处理文件传输通道
    if(tcp_fileSocket->state() == QAbstractSocket::UnconnectedState)
    {
        //获取新的客户端连接
        tcp_fileSocket = tcpServer->nextPendingConnection();

        //关联相关槽函数
        connect(tcp_fileSocket,SIGNAL(disconnected()),this,SLOT(onFileClientDisconnectedFunc()));
        connect(tcp_fileSocket,SIGNAL(readyRead()),this,SLOT(updateServerProgressFunc()));

        //Qt5.15之前是使用下面的这种方式
        // connect(tcp_textSocket,SIGNAL(error(QAbstractSocket::SocketError)),this
        //         ,SLOT(displayErrorInfoFunc(QAbstractSocket::SocketError)));

        //Qt6.5.3新版本改为errorOccurred
        connect(tcp_textSocket,SIGNAL(errorOccurred(QAbstractSocket::SocketError)),this
                ,SLOT(displayErrorInfoFunc(QAbstractSocket::SocketError)));
    }

    ui->plainTextEdit_msgList->appendPlainText("\n[**************有客户端连接**************]");
}

//文本通道槽函数

//文本socket断开连接处理
void FileTransferServerDialog::onTextClientDisconnectedFunc(){
    ui->plainTextEdit_msgList->appendPlainText("[**************客户端已断开和服务端的连接**************]");
    tcp_textSocket->close();
}
//读取客户端发送的文本数据
void FileTransferServerDialog::onTextSocketReadyReadFunc(){
    QDateTime currentDateTime = QDateTime::currentDateTime();
    QString dateTimeStr = currentDateTime.toString("yyyy-MM-dd hh:mm:ss");
    QString messageTemp;
    while(tcp_textSocket->canReadLine())
    {

        messageTemp.append(tcp_textSocket->readLine());
    }
    ui->plainTextEdit_msgList->appendPlainText(dateTimeStr+"->[客户端消息]:"+messageTemp);
}

//文件通道槽函数
//文件socket连接成功处理
void FileTransferServerDialog::onFileClientConnectedFunc(){
    ui->plainTextEdit_msgList->appendPlainText("[文件传输通道已连接...]");

}
//文件socket断开连接处理
void FileTransferServerDialog::onFileClientDisconnectedFunc(){
    tcp_fileSocket->close();
    ui->plainTextEdit_msgList->appendPlainText("[文件传输通道已断开...]");
}

//业务逻辑槽函数
//更新文件接收进度条百分比
void FileTransferServerDialog::updateServerProgressFunc(){
    //获取当前系统时间
    QDateTime currentDateTime = QDateTime::currentDateTime();
    QString dateTimeStr = currentDateTime.toString("yyyy-MM-dd hh:mm:ss");

    //QDataStream 要从 tcp_fileSocket 接收 客户端发送过来的数据
    QDataStream in(tcp_fileSocket);
    //1.接收文件头信息
    if(fileBytesReceived <= sizeof(qint64)*2)
    {
        //接收文件总大小和文件名长度
        //tcp_fileSocket->bytesAvailable():返回当前套接字缓冲区中可供读取的字节数
        //套接字缓冲区有至少 2个 qint64 的数据，且文件名长度未读取过
        if((tcp_fileSocket->bytesAvailable() >= sizeof(qint64)*2) && (fileNameLength == 0))
        {
            // 从流中读取文件总大小和文件名长度（qint64 类型）
            in >> fileTotalBytes >> fileNameLength;
            // 已接收字节数增加 2个 qint64 的大小（8字节 * 2 = 16字节）
            fileBytesReceived += sizeof(qint64)*2;
        }

        //接收文件名
        if((tcp_fileSocket->bytesAvailable() >= fileNameLength) && (fileNameLength != 0))
        {
            // 从流中读取文件名（QString 类型）
            in >> fileName;
            // 在日志框中记录开始接收文件的信息（时间 + 文件名）
            ui->plainTextEdit_msgList->appendPlainText(QString("[%1 开始接收文件 %2 ...]").arg(dateTimeStr).arg(fileName));
            // 已接收字节数增加文件名的字节数（fileNameLength）
            fileBytesReceived += fileNameLength;

            //创建本地文件,路径是文件的目录+文件名
            localFile = new QFile(QApplication::applicationDirPath() + "/" + fileName);
            if(!localFile->open(QFile::WriteOnly))
            {
                QMessageBox::critical(this,"警告","文件打开失败请重新检查");
                delete localFile;
                localFile = nullptr;
                return;
            }
        }
        else
        {
            return;
        }
    }

    //2.接收文件内容
    if(fileBytesReceived < fileTotalBytes)
    {
        //读取所有可用的数据(可能一次性读取多个数据包)
        buffer = tcp_fileSocket->readAll();
        //将数据写入到本地文件
        localFile->write(buffer);

        //更新已经接收的字节数
        fileBytesReceived += buffer.size();
        buffer.clear();//清空临时数据块

        //更新接收文件进度条效果
        ui->progressBar->setMaximum(fileTotalBytes);
        ui->progressBar->setValue(fileBytesReceived);
    }

    //3.传输完成的处理工作
    if(fileTotalBytes == fileBytesReceived)
    {
        //关闭文件
        localFile->close();
        //记录传输成功日志
        ui->plainTextEdit_msgList->appendPlainText(QString("[%1 文件 %2 接收成功]").arg(dateTimeStr).arg(fileName));

        //重置文件传输相关变量(为了下一次使用)
        fileTotalBytes = 0;//文件总字节
        fileBytesReceived = 0;//已经收文件大小
        fileNameLength = 0;//文件名长度(按照字节计算)

        //删除指针
        delete localFile;
        localFile = nullptr;
    }
}
//显示socket错误信息
void FileTransferServerDialog::displayErrorInfoFunc(QAbstractSocket::SocketError socketError){
    //文件传输有错误:关闭文件传输套接字，并且传输进度条归0
    tcp_fileSocket->close();
    ui->progressBar->reset();
}



//窗口关闭事件处理(停止监听并释放资源)
void FileTransferServerDialog::closeEvent(QCloseEvent *event)
{
    if(tcpServer->isListening())
    {
        tcpServer->close();
    }
    event->accept();

};

//系统托盘函数
void FileTransferServerDialog::mySystemTrayFunc()
{
    QIcon icon(":/images/logo.ico");
    mySystemTrays = new QSystemTrayIcon(this);
    mySystemTrays->setIcon(icon);

    //提示消息
    mySystemTrays->setToolTip("Tcp服务端");

    qMiniAction = new QAction("服务端最小化",this);
    connect(qMiniAction,SIGNAL(triggered()),this,SLOT(hide()));

    qRestoreAction = new QAction("服务端恢复显示",this);
    connect(qRestoreAction,SIGNAL(triggered()),this,SLOT(show()));

    qExitAction = new QAction("退出服务端");
    connect(qExitAction,SIGNAL(triggered()),this,SLOT(quit()));

    //添加到服务端右下角菜单栏
    pContextMenu = new QMenu(this);
    pContextMenu->addAction(qMiniAction);
    pContextMenu->addAction(qRestoreAction);
    pContextMenu->addAction(qExitAction);

    //设置菜单为系统托盘的菜单
    mySystemTrays->setContextMenu(pContextMenu);

    //显示系统托盘
    mySystemTrays->show();
}
